home *** CD-ROM | disk | FTP | other *** search
/ MacAddict 83 / MacAddict_083_2003-07.iso / mac / Software / Development / VLC Source 0.5.3.dmg / src / misc / cpu.c < prev    next >
C/C++ Source or Header  |  2002-12-12  |  10KB  |  325 lines

  1. /*****************************************************************************
  2.  * cpu.c: CPU detection code
  3.  *****************************************************************************
  4.  * Copyright (C) 1998-2002 VideoLAN
  5.  * $Id: cpu.c,v 1.10 2002/12/06 16:34:08 sam Exp $
  6.  *
  7.  * Authors: Samuel Hocevar <sam@zoy.org>
  8.  *          Christophe Massiot <massiot@via.ecp.fr>
  9.  *          Eugenio Jarosiewicz <ej0@cise.ufl.eduEujenio>
  10.  *
  11.  * This program is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  *
  16.  * This program is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  *
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this program; if not, write to the Free Software
  23.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  24.  *****************************************************************************/
  25.  
  26. /*****************************************************************************
  27.  * Preamble
  28.  *****************************************************************************/
  29. #include <vlc/vlc.h>
  30.  
  31. #ifdef HAVE_SIGNAL_H
  32. #   include <signal.h>                            /* SIGHUP, SIGINT, SIGKILL */
  33. #   include <setjmp.h>                                    /* longjmp, setjmp */
  34. #endif
  35.  
  36. #ifdef SYS_DARWIN
  37. #   include <mach/mach.h>                               /* AltiVec detection */
  38. #   include <mach/mach_error.h>       /* some day the header files||compiler *
  39.                                                        will define it for us */
  40. #   include <mach/bootstrap.h>
  41. #endif
  42.  
  43. #include "vlc_cpu.h"
  44.  
  45. /*****************************************************************************
  46.  * Local prototypes
  47.  *****************************************************************************/
  48. #ifdef HAVE_SIGNAL_H
  49. static void SigHandler   ( int );
  50. #endif
  51.  
  52. /*****************************************************************************
  53.  * Global variables - they're needed for signal handling
  54.  *****************************************************************************/
  55. #ifdef HAVE_SIGNAL_H
  56. static jmp_buf env;
  57. static int     i_illegal;
  58. #if defined( __i386__ )
  59. static char   *psz_capability;
  60. #endif
  61. #endif
  62.  
  63. /*****************************************************************************
  64.  * CPUCapabilities: get the CPU capabilities
  65.  *****************************************************************************
  66.  * This function is called to list extensions the CPU may have.
  67.  *****************************************************************************/
  68. uint32_t CPUCapabilities( void )
  69. {
  70.     volatile uint32_t i_capabilities = CPU_CAPABILITY_NONE;
  71.  
  72. #if defined( SYS_DARWIN )
  73.     struct host_basic_info hi;
  74.     kern_return_t          ret;
  75.     host_name_port_t       host;
  76.  
  77.     int i_size;
  78.     char *psz_name, *psz_subname;
  79.  
  80.     i_capabilities |= CPU_CAPABILITY_FPU;
  81.  
  82.     /* Should 'never' fail? */
  83.     host = mach_host_self();
  84.  
  85.     i_size = sizeof( hi ) / sizeof( int );
  86.     ret = host_info( host, HOST_BASIC_INFO, ( host_info_t )&hi, &i_size );
  87.  
  88.     if( ret != KERN_SUCCESS )
  89.     {
  90.         fprintf( stderr, "error: couldn't get CPU information\n" );
  91.         return i_capabilities;
  92.     }
  93.  
  94.     slot_name( hi.cpu_type, hi.cpu_subtype, &psz_name, &psz_subname );
  95.     /* FIXME: need better way to detect newer proccessors.
  96.      * could do strncmp(a,b,5), but that's real ugly */
  97.     if( !strcmp(psz_name, "ppc7400") || !strcmp(psz_name, "ppc7450") )
  98.     {
  99.         i_capabilities |= CPU_CAPABILITY_ALTIVEC;
  100.     }
  101.  
  102.     return i_capabilities;
  103.  
  104. #elif defined( __i386__ )
  105.     volatile unsigned int  i_eax, i_ebx, i_ecx, i_edx;
  106.     volatile vlc_bool_t    b_amd;
  107.  
  108.     /* Needed for x86 CPU capabilities detection */
  109. #   define cpuid( reg )                    \
  110.         asm volatile ( "pushl %%ebx\n\t"   \
  111.                        "cpuid\n\t"         \
  112.                        "movl %%ebx,%1\n\t" \
  113.                        "popl %%ebx\n\t"    \
  114.                      : "=a" ( i_eax ),     \
  115.                        "=r" ( i_ebx ),     \
  116.                        "=c" ( i_ecx ),     \
  117.                        "=d" ( i_edx )      \
  118.                      : "a"  ( reg )        \
  119.                      : "cc" );
  120.  
  121. #   if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) \
  122.      && defined( HAVE_SIGNAL_H )
  123.     void (*pf_sigill) (int) = signal( SIGILL, SigHandler );
  124. #   endif
  125.  
  126.     i_capabilities |= CPU_CAPABILITY_FPU;
  127.  
  128.     /* test for a 486 CPU */
  129.     asm volatile ( "pushl %%ebx\n\t"
  130.                    "pushfl\n\t"
  131.                    "popl %%eax\n\t"
  132.                    "movl %%eax, %%ebx\n\t"
  133.                    "xorl $0x200000, %%eax\n\t"
  134.                    "pushl %%eax\n\t"
  135.                    "popfl\n\t"
  136.                    "pushfl\n\t"
  137.                    "popl %%eax\n\t"
  138.                    "movl %%ebx,%1\n\t"
  139.                    "popl %%ebx\n\t"
  140.                  : "=a" ( i_eax ),
  141.                    "=r" ( i_ebx )
  142.                  :
  143.                  : "cc" );
  144.  
  145.     if( i_eax == i_ebx )
  146.     {
  147. #   if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) \
  148.      && defined( HAVE_SIGNAL_H )
  149.         signal( SIGILL, pf_sigill );
  150. #   endif
  151.         return i_capabilities;
  152.     }
  153.  
  154.     i_capabilities |= CPU_CAPABILITY_486;
  155.  
  156.     /* the CPU supports the CPUID instruction - get its level */
  157.     cpuid( 0x00000000 );
  158.  
  159.     if( !i_eax )
  160.     {
  161. #   if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) \
  162.      && defined( HAVE_SIGNAL_H )
  163.         signal( SIGILL, pf_sigill );
  164. #   endif
  165.         return i_capabilities;
  166.     }
  167.  
  168.     /* FIXME: this isn't correct, since some 486s have cpuid */
  169.     i_capabilities |= CPU_CAPABILITY_586;
  170.  
  171.     /* borrowed from mpeg2dec */
  172.     b_amd = ( i_ebx == 0x68747541 ) && ( i_ecx == 0x444d4163 )
  173.                     && ( i_edx == 0x69746e65 );
  174.  
  175.     /* test for the MMX flag */
  176.     cpuid( 0x00000001 );
  177.  
  178.     if( ! (i_edx & 0x00800000) )
  179.     {
  180. #   if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) \
  181.      && defined( HAVE_SIGNAL_H )
  182.         signal( SIGILL, pf_sigill );
  183. #   endif
  184.         return i_capabilities;
  185.     }
  186.  
  187.     i_capabilities |= CPU_CAPABILITY_MMX;
  188.  
  189.     if( i_edx & 0x02000000 )
  190.     {
  191.         i_capabilities |= CPU_CAPABILITY_MMXEXT;
  192.  
  193. #   ifdef CAN_COMPILE_SSE
  194.         /* We test if OS supports the SSE instructions */
  195.         psz_capability = "SSE";
  196.         i_illegal = 0;
  197.  
  198.         if( setjmp( env ) == 0 )
  199.         {
  200.             /* Test a SSE instruction */
  201.             __asm__ __volatile__ ( "xorps %%xmm0,%%xmm0\n" : : );
  202.         }
  203.  
  204.         if( i_illegal == 0 )
  205.         {
  206.             i_capabilities |= CPU_CAPABILITY_SSE;
  207.         }
  208. #   endif
  209.     }
  210.  
  211.     /* test for additional capabilities */
  212.     cpuid( 0x80000000 );
  213.  
  214.     if( i_eax < 0x80000001 )
  215.     {
  216. #   if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) \
  217.      && defined( HAVE_SIGNAL_H )
  218.         signal( SIGILL, pf_sigill );
  219. #   endif
  220.         return i_capabilities;
  221.     }
  222.  
  223.     /* list these additional capabilities */
  224.     cpuid( 0x80000001 );
  225.  
  226. #   ifdef CAN_COMPILE_3DNOW
  227.     if( i_edx & 0x80000000 )
  228.     {
  229.         psz_capability = "3D Now!";
  230.         i_illegal = 0;
  231.  
  232.         if( setjmp( env ) == 0 )
  233.         {
  234.             /* Test a 3D Now! instruction */
  235.             __asm__ __volatile__ ( "pfadd %%mm0,%%mm0\n" "femms\n" : : );
  236.         }
  237.  
  238.         if( i_illegal == 0 )
  239.         {
  240.             i_capabilities |= CPU_CAPABILITY_3DNOW;
  241.         }
  242.     }
  243. #   endif
  244.  
  245.     if( b_amd && ( i_edx & 0x00400000 ) )
  246.     {
  247.         i_capabilities |= CPU_CAPABILITY_MMXEXT;
  248.     }
  249.  
  250. #   if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) \
  251.      && defined( HAVE_SIGNAL_H )
  252.     signal( SIGILL, pf_sigill );
  253. #   endif
  254.     return i_capabilities;
  255.  
  256. #elif defined( __powerpc__ )
  257.  
  258. #   ifdef CAN_COMPILE_ALTIVEC && defined( HAVE_SIGNAL_H )
  259.     void (*pf_sigill) (int) = signal( SIGILL, SigHandler );
  260.  
  261.     i_capabilities |= CPU_CAPABILITY_FPU;
  262.  
  263.     i_illegal = 0;
  264.  
  265.     if( setjmp( env ) == 0 )
  266.     {
  267.         asm volatile ("mtspr 256, %0\n\t"
  268.                       "vand %%v0, %%v0, %%v0"
  269.                       :
  270.                       : "r" (-1));
  271.     }
  272.  
  273.     if( i_illegal == 0 )
  274.     {
  275.         i_capabilities |= CPU_CAPABILITY_ALTIVEC;
  276.     }
  277.  
  278.     signal( SIGILL, pf_sigill );
  279. #   endif
  280.  
  281.     return i_capabilities;
  282.  
  283. #elif defined( __sparc__ )
  284.  
  285.     i_capabilities |= CPU_CAPABILITY_FPU;
  286.     return i_capabilities;
  287.  
  288. #else
  289.     /* default behaviour */
  290.     return i_capabilities;
  291.  
  292. #endif
  293. }
  294.  
  295. /*****************************************************************************
  296.  * SigHandler: system signal handler
  297.  *****************************************************************************
  298.  * This function is called when an illegal instruction signal is received by
  299.  * the program. We use this function to test OS and CPU capabilities
  300.  *****************************************************************************/
  301. #if defined( HAVE_SIGNAL_H )
  302. static void SigHandler( int i_signal )
  303. {
  304.     /* Acknowledge the signal received */
  305.     i_illegal = 1;
  306.  
  307. #ifdef HAVE_SIGRELSE
  308.     sigrelse( i_signal );
  309. #endif
  310.  
  311. #if defined( __i386__ )
  312.     fprintf( stderr, "warning: your CPU has %s instructions, but not your "
  313.                      "operating system.\n", psz_capability );
  314.     fprintf( stderr, "         some optimizations will be disabled unless "
  315.                      "you upgrade your OS\n" );
  316. #   if defined( SYS_LINUX )
  317.     fprintf( stderr, "         (for instance Linux kernel 2.4.x or later)\n" );
  318. #   endif
  319. #endif
  320.  
  321.     longjmp( env, 1 );
  322. }
  323. #endif
  324.  
  325.